package admin

import (
	"context"
	"ia/apps/admin/dto/oin"
	oinadmin "ia/apps/admin/dto/oin/admin"
	ooutadmin "ia/apps/admin/dto/oout/admin"
	"ia/apps/admin/middleware/logsink"
	"ia/apps/admin/repository/query"
	modeladmin "ia/common/model/admin"
	"ia/common/storage"
	"ia/common/support/global"

	"github.com/kataras/golog"
	"gorm.io/gorm"
)

type AdminPolicyService interface {
	DeleteByIdList([]int64) error
	GetTable(oin.VxeTableIn) ([]*modeladmin.AdminPolicy, int64, error)
	GetList() ([]*ooutadmin.AdminPolicyOut, error)
	ReloadPolicy() error
	Log(oinadmin.AdminPolicyOfLogIn) error
}

func NewAdminPolicyService() *adminPolicyService {
	return &adminPolicyService{}
}

type adminPolicyService struct{}

func (impl *adminPolicyService) DeleteByIdList(idList []int64) (err error) {
	var policyList = make([]*modeladmin.AdminPolicy, 0)
	if len(idList) > 0 {
		if err = storage.GDB1.Find(&policyList, "id in ?", idList).Error; err != nil {
			return
		}
	}
	if err = storage.GDB1.Transaction(func(tx *gorm.DB) error {
		if err = tx.Delete(&modeladmin.AdminPolicy{}, "id in ?", idList).Error; err != nil {
			return err
		}
		if err = tx.Delete(&modeladmin.AdminRolePolicy{}, "pid in ?", idList).Error; err != nil {
			return err
		}
		for _, v := range policyList {
			if err = tx.Delete(&modeladmin.CasbinRule{},
				"ptype='p' AND v2=? AND v3=? AND v4=?", v.V2, v.V3, v.V4).Error; err != nil {
				return err
			}
		}
		return nil
	}); err != nil {
		return
	}
	return
}

func (impl *adminPolicyService) GetTable(in oin.VxeTableIn) (rows []*modeladmin.AdminPolicy, total int64, err error) {
	if err = storage.GDB1.Model(&modeladmin.AdminPolicy{}).Count(&total).Error; err != nil {
		return
	}
	if err = storage.GDB1.
		Offset(in.Offset()).Limit(in.PageSize).
		Find(&rows).Error; err != nil {
		return
	}
	return
}

func (impl *adminPolicyService) GetList() (rows []*ooutadmin.AdminPolicyOut, err error) {
	m := query.Use(storage.GDB1).AdminPolicyOut
	do := m.WithContext(context.Background())

	rows, err = do.Order(m.GroupName).Find()
	return
}

func (impl *adminPolicyService) ReloadPolicy() (err error) {
	err = storage.GDB1.Transaction(func(tx *gorm.DB) error {
		for _, v := range ooutadmin.GIfaceList {
			policy := modeladmin.AdminPolicy{
				GroupName: v.GroupName,
				Name:      v.Name,
				Memo:      v.Memo,
				IsSystem:  true,
				V1:        global.GConfig.App.Own.Tenant,
				V2:        v.Path,
				V3:        v.Method,
				V4:        ".*",
				V5:        "",
			}
			if err := tx.Where(&policy).FirstOrCreate(&policy).Error; err != nil {
				return err
			}
		}
		// TODO 1 删除后来又取消的;2 调整后来又修改的
		return nil
	})
	return
}

func (impl *adminPolicyService) Log(in oinadmin.AdminPolicyOfLogIn) (err error) {
	if len(in.IdList) > 0 {
		if err = storage.GDB1.Model(&modeladmin.AdminPolicy{}).
			Where("id in ?", in.IdList).Update("logable", in.Operation).Error; err != nil {
			return
		}
		if err := storage.GDB1.Find(&logsink.GPolicyLogList, "logable=TRUE").Error; err != nil {
			golog.Error("刷新policy log 缓存失败,错误=%v", err)
		}
	}
	return
}
